#include <iostream> // cout/cin
#include <string>
#include <stdlib.h> //atoi
#include "Interface.h"
#include "idxMasterfile/util.h"
#include "idxMasterfile/getche.h"

Interface::Interface() : controlador() {}

void Interface::correr()
{
	limpiarPantalla();
	bool correr = true;
	while (correr)
	{
		cout << endl;
		cout << "Carpeta de indexacion actual: " << controlador.pathDir << endl << endl;
		cout << "Elija una opcion por numero:" << endl;
		cout << "1. Recrear indexacion (eliminara la indexacion actual)." << endl;
		cout << "2. Cambiar directorio de archivos de indexacion." << endl;
		cout << "3. Indexar archivo." << endl;
		cout << "4. Indexar todos los archivos de un directorio." << endl;
		cout << "5. Buscar por autor." << endl;
		cout << "6. Buscar por titulo." << endl;
		cout << "7. Buscar por frase." << endl;
		cout << "8. Ver estadisticas de las busquedas realizadas." << endl;
		cout << "9. Salir del programa." << endl << endl;
		string s;
		cin >> s;
		int opcion = atoi(s.c_str());
		cout << endl;
		switch(opcion)
		{
			case 1:
				cout << "Esta seguro? Si(s) / No(n)" << endl;
				getLineaNorm(s);
				if (s[0] == 's') reindexar();
				break;
			case 2:
				cout << "Ingrese el path del nuevo directorio:" << endl;
				getLinea(s);
				revisarPath(s);
				cambiarDestino(s);
				break;
			case 3:
				cout << "Ingrese el path del archivo:" << endl;
				getLinea(s);
				indexarArchivo(s);
				break;
			case 4:
				cout << "Ingrese el path del directorio:" << endl;
				getLinea(s);
				revisarPath(s);
				indexarDirectorio(s);
				break;
			case 5:
				cout << "Ingrese el autor:" << endl;
				getLineaNorm(s);
				buscarAutor(s);
				break;
			case 6:
				cout << "Ingrese el titulo:" << endl;
				getLineaNorm(s);
				buscarTitulo(s);
				break;
			case 7:
				cout << "Ingrese la frase:" << endl;
				getLineaNorm(s);
				buscarFrase(s);
				break;
			case 8:
				mostrarEstadisticas();
				break;
			case 9:
				correr = false;
				break;
			default:
				cout << "La opcion ingresada es invalida." << endl;
				getche(); // para parar el programa hasta que el usuario presione una tecla
				break;
		}
		getche(); // para parar el programa hasta que el usuario presione una tecla
	 	limpiarPantalla();
	}
	return;
}

void Interface::mostrarResultados(vector<RegistroMF> &results)
{
	limpiarPantalla();
	bool correr = true;
	while (correr)
	{
		cout << endl;
		cout << "Elija una opcion por numero para ver la letra:" << endl;
		cout << "0. Volver al menu principal." << endl;
		cout << "Matches:" << endl;
		size_t cont = 1;
		for (vector<RegistroMF>::iterator it = results.begin(); it != results.end(); ++it)
		{
			string tmp;
			it->sCabecera(tmp);
			cout << cont++ << "." << tmp << endl;
		}
		string s;
		cin >> s;
		size_t opcion = atoi(s.c_str());
		cout << endl;
		if (opcion <= 0) { 
			correr = false;
		}
		else {
			getche(); // para parar el programa hasta que el usuario presione una tecla
			limpiarPantalla();

			if (opcion-1 < results.size()) {
				cout << results[opcion-1] << endl;
			}
			else {
				cout << "La opcion ingresada es invalida." << endl;
			}

			getche();
			limpiarPantalla();
		}
	}
}

/**
 * @brief Lee una linea de consola y la devuelve
 * @param s string donde se guardara la linea
 */
void Interface::getLinea(string &s)
{
	string tmp;
	cin >> s;
	getline(cin, tmp);
	s += tmp;
}

void Interface::getLineaNorm(string &s)
{
	getLinea(s);
	normalizarYlimpiar(s);
}

/**
 * @brief Busca una cancion por titulo, e imprime por pantalla acorde al resultado.
 * @param titulo un puntero a un string que contiene el titulo a buscar.
 */
void Interface::buscarTitulo(string &titulo)
{
	vector<RegistroMF> vect;
	controlador.buscarTitulo(titulo,vect);
	if (vect.size() <= 0)
	{
		cout << "No se han encontrado canciones con ese titulo." << endl;
	}
	else
	{
		vector<string> cancionesEncontradas = obtenerCanciones(vect);
		controlador.estadisticas.agregarTitulo(titulo);
		controlador.estadisticas.agregarTituloCanciones(cancionesEncontradas);
		controlador.estadisticas.agregarCanciones(cancionesEncontradas);
		
		mostrarResultados(vect);
	}
}

/**
 * @brief Busca una cancion por autor, e imprime por pantalla acorde al resultado.
 * @param autor un puntero a un string que contiene el autor a buscar.
 */
void Interface::buscarAutor(string &autor)
{
	vector<RegistroMF> vect;
	controlador.buscarAutor(autor,vect);
	if (vect.size() <= 0)
	{
		cout << "No se han encontrado canciones de ese autor." << endl;
	}
	else
	{
		vector<string> cancionesEncontradas = obtenerCanciones(vect);
		controlador.estadisticas.agregarAutor(autor);
		controlador.estadisticas.agregarAutorCanciones(cancionesEncontradas);
		controlador.estadisticas.agregarCanciones(cancionesEncontradas);
		
		mostrarResultados(vect);
	}
}

/**
 * @brief Busca una cancion por frases, e imprime por pantalla acorde al resultado.
 * @param frase un puntero a un string que contiene una frase.
 */
void Interface::buscarFrase(string &frase)
{
	vector<RegistroMF> vect;
	controlador.buscarFrase(frase,vect);
	if (vect.size() <= 0)
	{
		cout << "No se han encontrado canciones con esta frase" << endl;
	}
	else
	{
		vector<string> cancionesEncontradas = obtenerCanciones(vect);
		controlador.estadisticas.agregarFrase(frase);
		controlador.estadisticas.agregarFraseCanciones(cancionesEncontradas);
		controlador.estadisticas.agregarCanciones(cancionesEncontradas);
		
		mostrarResultados(vect);
	}	
}

/**
 * @brief Convierte un vector de RegistroMF a un vector de string (nombre de canciones).
 * @param Recibe un vector de RegistroMF.
 */
vector<string> Interface::obtenerCanciones(vector<RegistroMF> vect) {

	vector<string> vectorRetorno;

	for(vector<RegistroMF>::iterator it = vect.begin(); it != vect.end(); ++it)
	{
		string tmp;
		it->sCabecera(tmp);
		vectorRetorno.push_back(tmp);
	}
	
	return vectorRetorno;
}

/**
 * @brief Submenu para mostrar diferentes estadisticas.
 */
void Interface::mostrarEstadisticas() {
	limpiarPantalla();
	bool correr = true;
	while (correr)
	{
		cout << endl;
		cout << "Elija una opcion por numero para la opcion deseada:" << endl;
		cout << "0. Volver al menu principal." << endl;
		cout << "Estadisticas:" << endl;
		cout << "1. Estadistica de las busquedas por titulos" << endl;
		cout << "2. Estadistica de las busquedas por autores" << endl;
		cout << "3. Estadistica de las busquedas por frases" << endl;
		cout << "4. Estadistica de las canciones resultados de todas las busquedas" << endl;
		cout << "5. Resetear las estadisticas" << endl;
		cout << "6. Cambiar la cantidad maxima de resultados en las tablas de estadisticas" << endl << endl;
		
		string s;
		cin >> s;
		int opcion = atoi(s.c_str());
		cout << endl;
		switch(opcion)
		{
			case 0:
				correr = false;
				break;
			case 1:
			 	limpiarPantalla();
				cout << endl;
				cout << "Estadistica de las busquedas por titulo" << endl;
				cout << endl;
				cout << "Cantidad de veces que ha buscado por titulo: "
						<< controlador.estadisticas.getCantBusquedaTitulos() << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getTitulosEstadistica(),"Titulos buscados");
				cout << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getTitulosCancionesEstadistica(),"Canciones encontradas");
				cout << endl;
				getche();
				getche();
				break;
			case 2:
			 	limpiarPantalla();
				cout << endl;
				cout << "Estadistica de las busquedas por autor" << endl;
				cout << endl;
				cout << "Cantidad de veces que ha buscado por autor: " << controlador.estadisticas.getCantBusquedaAutores() << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getAutoresEstadistica(),"Autores buscados");
				cout << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getAutoresCancionesEstadistica(),"Canciones encontradas");
				cout << endl;
				getche();
				getche();
				break;
			case 3:
			 	limpiarPantalla();
				cout << endl;
				cout << "Estadistica de las busquedas por frase" << endl;
				cout << endl;
				cout << "Cantidad de veces que ha buscado por frase: " << controlador.estadisticas.getCantBusquedaFrases() << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getFrasesEstadistica(),"Frases buscadas");
				cout << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getFrasesCancionesEstadistica(),"Canciones encontradas");
				cout << endl;
				getche();
				getche();
				break;
			case 4:
			 	limpiarPantalla();
				cout << endl;
				cout << "Estadistica de las canciones resultados de todas las busquedas" << endl;
				cout << endl;
				cout << "Cantidad total de veces que ha hecho busquedas: " << controlador.estadisticas.getCantBusquedaCanciones() << endl;
				cout << endl;
				cout << endl;
				controlador.estadisticas.imprimirTabla(controlador.estadisticas.getCancionesEstadistica(),"Canciones resultados");
				cout << endl;
				getche();
				getche();
				break;
			case 5:
				cout << "Esta seguro? Si(s) / No(n)" << endl;
				getLineaNorm(s);
				if (s[0] == 's') {
					controlador.estadisticas.reset();
					cout << endl;
					cout << "Se ha reseteado las estadisticas con exito" << endl;
				}
				getche();
				break;
			case 6:
				cout << "Que cantidad desea?" << endl;
				getLineaNorm(s);
				opcion = atoi(s.c_str());
				if ( opcion > 0 ) {
					controlador.estadisticas.setCantAmostrar( opcion );
					cout << endl;
					cout << "Se ha cambiado la cantidad con exito" << endl;
				}
				else {
					cout << "Lo ingresado no es correcto" << endl;
				}
				getche();
				break;
			default:
				cout << "La opcion ingresada es invalida." << endl;
				getche();
				getche(); // para parar el programa hasta que el usuario presione una tecla
				break;
		}

	 	limpiarPantalla();
	}
}


/**
 * @brief Permite agregar un archivo al programa.
 * @param frase un puntero a un string que contiene una frase.
 */
void Interface::indexarArchivo(string &path)
{
	RegistroMF reg;
	bool result = controlador.indexarArchivo(path, reg);
	if (result)
	{
		string tmp;
		reg.sCabecera(tmp);
		cout << "Se ha indexado con exito: " << tmp << endl;
	}
	else
	{
		cout << "Ha fallado la indexacion del archivo: " << path << endl;
		cout << "Compruebe que el archivo exista, tenga formato correcto "
				"y no fuera previamente indexado." << endl;
	}
}

/**
 * @brief Permite agregar todos los archivos de un directorio al programa.
 * @param frase puntero a string con el path del directorio.
 */
void Interface::indexarDirectorio(string &path)
{
	vector<RegistroMF> registros;
	bool result = controlador.indexarDirectorio(path, registros);
	if (result)
	{
		if (registros.size() > 0)
		{
			for(vector<RegistroMF>::iterator it = registros.begin(); it != registros.end(); ++it)
			{
				string tmp;
				it->sCabecera(tmp);
				cout << "Se ha indexado con exito: " << tmp << endl;
			}
		}
		else
		{
			cout << "No se han encontrado archivos para indexar." << endl;
		}
	}
	else
	{
		cout << "Ha fallado la indexacion del directorio: " << path << endl;
		cout << "Compruebe que el directorio exista y tenga permisos apropiados"<< endl << endl;
	}
}

/**
 * @brief Cambia el directorio destino de la aplication
 * @param path puntero a string hacia el nuevo directorio
 */
void Interface::cambiarDestino(string &path)
{
	if (controlador.cambiarDestino(path))
	{
		cout << "Se ha cambiado el directorio exitosamente." << endl;
	}
	else
	{
		cout << "No se ha podido acceder al directorio pedido." << endl;
	}
}

void Interface::revisarPath(string &s)
{
	if (s[s.length()-1] != '/') s.append("/");
}

/**
 * @brief Elimina la indexacion actual
 */
void Interface::reindexar()
{
	controlador.reindexar();
	cout << "Operacion realizada." << endl;
}

/**
 * @brief Espera a que el usuario presione una tecla y limpia la pantalla
 */
void Interface::limpiarPantalla()
{
	if (system("reset")) {
		int i = system("cls");
		(void)i;		// suprimir warning "unused"
	} 
}

